﻿using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Data.SqlClient;
using System.Windows.Forms;
using Curriculum.Controls;
using Curriculum.DataSet;
using DevExpress.XtraGrid.Views.Grid;
using E4RPDevExpress;
using E4RPPrintManager;
using E4RPTools;

namespace Curriculum
{
    public class BackOfficeController
    {
        private SqlConnection _connection;

        public IWin32Window OwnerWindow { get; set; }


        private void PublishAndShowErrorMessage(Exception e, string errorMessage)
        {
            ExceptionPublisher.Publish(ConfigurationManager.AppSettings["LogFile"], e);
            ExceptionPublisher.ShowErrorMessage(OwnerWindow, errorMessage, "Gestão Movimentos");
        }

        private void FixConnection()
        {
            if (_connection.State == ConnectionState.Open)
                _connection.Close();
            _connection.Open();
        }

        private CandidatePrintDataSet GetCandidatePrint(long candidateId, long? vacancyId)
        {
            FixConnection();
            var sqlTransaction = _connection.BeginTransaction();
            try
            {
                var dataSet = Database.GetCandidatePrint(sqlTransaction, candidateId, vacancyId);
                sqlTransaction.Commit();
                return dataSet;
            }
            catch (Exception e)
            {
                sqlTransaction.Rollback();
                PublishAndShowErrorMessage(e, "Não foi possível ler o candidato.");
                return new CandidatePrintDataSet();
            }
        }


        public bool IsUserValid(string userName, string password)
        {
            var dataSource = ConfigurationManager.AppSettings["FonteDados"];
            var databaseName = ConfigurationManager.AppSettings["NomeBaseDados"];
            var connectionString = String.Format("Data Source={0};Initial Catalog={1};User ID={2};Password={3};MultipleActiveResultSets=True;", dataSource, databaseName, userName, password);
            try
            {
                _connection = new SqlConnection(connectionString);
                _connection.Open();
            }
            catch (Exception e)
            {
                PublishAndShowErrorMessage(e, "Utilizador sem acesso à base de dados.");
                return false;
            }
            return true;
        }
        

        #region Vacancy

        private void OnVacancySaved()
        {
            EventHandler<EventArgs> saved = VacancySaved;
            if (saved != null)
                saved(this, new EventArgs());
        }

        public event EventHandler<EventArgs> VacancySaved;

        public VacancyDataSet GetVacancies(string extendedFilter)
        {
            FixConnection();
            var sqlTransaction = _connection.BeginTransaction();
            try
            {
                var dataSet = Database.GetVacancies(sqlTransaction, extendedFilter);
                sqlTransaction.Commit();
                return dataSet;
            }
            catch (Exception e)
            {
                sqlTransaction.Rollback();
                PublishAndShowErrorMessage(e, "Não foi possível ler a lista de vagas.");
                return new VacancyDataSet();
            }
        }

        public VacancyDataSet GetVacancy(long vacancyId)
        {
            FixConnection();
            var sqlTransaction = _connection.BeginTransaction();
            try
            {
                var dataSet = Database.GetVacancy(sqlTransaction, vacancyId);
                sqlTransaction.Commit();
                return dataSet;
            }
            catch (Exception e)
            {
                sqlTransaction.Rollback();
                PublishAndShowErrorMessage(e, "Não foi possível ler a vaga.");
                return new VacancyDataSet();
            }
        }

        public bool CanDeleteVacancy(long vacancyId)
        {
            FixConnection();
            var sqlTransaction = _connection.BeginTransaction();
            try
            {
                var result = Database.ExistsCandidateVacancies(sqlTransaction, vacancyId);
                sqlTransaction.Commit();
                return !result;
            }
            catch (Exception e)
            {
                sqlTransaction.Rollback();
                PublishAndShowErrorMessage(e, "Não foi possível validar se pode eliminar a vaga.");
                return false;
            }
        }

        public void DeleteVacancy(long vacancyId)
        {
            FixConnection();
            var sqlTransaction = _connection.BeginTransaction();
            try
            {
                Database.DeleteVacancy(sqlTransaction, vacancyId);
                sqlTransaction.Commit();      
                OnVacancySaved();
            }
            catch (Exception e)
            {
                sqlTransaction.Rollback();
                PublishAndShowErrorMessage(e, "Não foi possível eliminar a vaga.");                
            }
        }

        public Result IsVacancyValid(VacancyDataSet dataset)
        {
            var result = new Result();
            var vacancy = dataset.Vacancy[0];
            if (vacancy.IsAreaNull() || vacancy.Area.Length == 0) result.Add("Area", "Por favor, preencha a área.");
            if (!vacancy.IsAreaNull() && vacancy.Area.Length > 1000) result.Add("Area", "A área excede os 1000 caracteres permitidos.");
            if (vacancy.IsSubAreaNull() || vacancy.SubArea.Length == 0) result.Add("SubArea", "Por favor, preencha a sub-área.");
            if (!vacancy.IsSubAreaNull() && vacancy.SubArea.Length > 1000) result.Add("SubArea", "A sub-área excede os 1000 caracteres permitidos.");
            if (vacancy.IsPositionNull() || vacancy.Position.Length == 0) result.Add("Position", "Por favor, preencha a função.");
            if (!vacancy.IsPositionNull() && vacancy.Position.Length > 1000) result.Add("Position", "A função excede os 1000 caracteres permitidos.");
            if (!vacancy.IsAcceptingStartNull() && !vacancy.IsAcceptingEndNull() && vacancy.AcceptingEnd < vacancy.AcceptingStart) 
                result.Add("AcceptingEnd", "A data de final de recutamento deve ser posterior à data inicial de recrutamento.");
            if (!vacancy.IsDescriptionNull() && vacancy.Description.Length > 1000) result.Add("Description", "A descrição excede os 1000 caracteres permitidos.");
            if (vacancy.Opennings < 0) result.Add("Opennings", "O número de vagas deve ser positivo.");
            return result;
        }

        public void SaveVacancy(VacancyDataSet dataset)
        {
            FixConnection();
            var sqlTransaction = _connection.BeginTransaction();
            try
            {
                Database.SaveVacancy(sqlTransaction, dataset.Vacancy[0]);
                sqlTransaction.Commit();
                OnVacancySaved();                
            }
            catch (Exception e)
            {
                sqlTransaction.Rollback();
                PublishAndShowErrorMessage(e, "Não foi possível gravar a vaga.");
            }
        }

        #endregion

        #region Position

        private void OnPositionSaved()
        {
            EventHandler<EventArgs> saved = PositionSaved;
            if (saved != null)
                saved(this, new EventArgs());
        }

        public event EventHandler<EventArgs> PositionSaved;

        public PositionDataSet GetPositions(string extendedFilter)
        {
            FixConnection();
            var sqlTransaction = _connection.BeginTransaction();
            try
            {
                var dataSet = Database.GetPositions(sqlTransaction, extendedFilter);
                sqlTransaction.Commit();
                return dataSet;
            }
            catch (Exception e)
            {
                sqlTransaction.Rollback();
                PublishAndShowErrorMessage(e, "Não foi possível ler a lista de funções.");
                return new PositionDataSet();
            }
        }

        public PositionDataSet GetPosition(long positionId)
        {
            FixConnection();
            var sqlTransaction = _connection.BeginTransaction();
            try
            {
                var dataSet = Database.GetPosition(sqlTransaction, positionId);
                sqlTransaction.Commit();
                return dataSet;
            }
            catch (Exception e)
            {
                sqlTransaction.Rollback();
                PublishAndShowErrorMessage(e, "Não foi possível ler a função.");
                return new PositionDataSet();
            }
        }

        public Result IsPositionValid(PositionDataSet dataset)
        {
            var result = new Result();
            var position = dataset.Position[0];
            if (position.IsAreaNull() || position.Area.Length == 0) result.Add("Area", "Por favor, preencha a área.");
            if (!position.IsAreaNull() && position.Area.Length > 1000) result.Add("Area", "A área excede os 1000 caracteres permitidos.");
            if (position.IsSubAreaNull() || position.SubArea.Length == 0) result.Add("SubArea", "Por favor, preencha a sub-área.");
            if (!position.IsSubAreaNull() && position.SubArea.Length > 1000) result.Add("SubArea", "A sub-área excede os 1000 caracteres permitidos.");
            if (position.IsNameNull() || position.Name.Length == 0) result.Add("Name", "Por favor, preencha o nome.");
            if (!position.IsNameNull() && position.Name.Length > 1000) result.Add("Name", "O nome excede os 1000 caracteres permitidos.");
            return result;
        }

        public void SavePosition(PositionDataSet dataset)
        {
            FixConnection();
            var sqlTransaction = _connection.BeginTransaction();
            try
            {
                Database.SavePosition(sqlTransaction, dataset.Position[0]);
                sqlTransaction.Commit();
                OnPositionSaved();
            }
            catch (Exception e)
            {
                sqlTransaction.Rollback();
                PublishAndShowErrorMessage(e, "Não foi possível gravar a função.");
            }
        }

        #endregion

        private void OnCandidateSaved()
        {
            EventHandler<EventArgs> saved = CandidateSaved;
            if (saved != null)
                saved(this, new EventArgs());
        }

        public CandidateVacancyDataSet GetCandidateVacancies(string extendedFilter)
        {
            FixConnection();
            var sqlTransaction = _connection.BeginTransaction();
            try
            {
                var dataSet = Database.GetCandidateVacancies(sqlTransaction, extendedFilter);
                sqlTransaction.Commit();
                return dataSet;
            }
            catch (Exception e)
            {
                sqlTransaction.Rollback();
                PublishAndShowErrorMessage(e, "Não foi possível ler a lista de candidatos e vagas.");
                return new CandidateVacancyDataSet();
            }
        }

        public CandidateDataSet GetCandidates(string extendedFilter)
        {
            FixConnection();
            var sqlTransaction = _connection.BeginTransaction();
            try
            {
                var dataSet = Database.GetCandidates(sqlTransaction, extendedFilter);
                sqlTransaction.Commit();
                return dataSet;
            }
            catch (Exception e)
            {
                sqlTransaction.Rollback();
                PublishAndShowErrorMessage(e, "Não foi possível ler a lista de candidatos.");
                return new CandidateDataSet();
            }
        }

        public CandidateDataSet GetCandidate(long candidateId)
        {
            FixConnection();
            var sqlTransaction = _connection.BeginTransaction();
            try
            {
                var dataSet = Database.GetCandidate(sqlTransaction, candidateId);
                sqlTransaction.Commit();
                return dataSet;
            }
            catch (Exception e)
            {
                sqlTransaction.Rollback();
                PublishAndShowErrorMessage(e, "Não foi possível ler o candidato.");
                return new CandidateDataSet();
            }
        }

        public byte[] GetCandidateAttachment(long candidateId)
        {
            FixConnection();
            var sqlTransaction = _connection.BeginTransaction();
            try
            {
                var attachment = Database.GetCandidateAttachment(sqlTransaction, candidateId);
                sqlTransaction.Commit();
                return attachment;
            }
            catch (Exception e)
            {
                sqlTransaction.Rollback();
                PublishAndShowErrorMessage(e, "Não foi possível ler o curriculum vitae do candidato.");
                return null;
            }
        }

        public event EventHandler<EventArgs> CandidateSaved;

        public void PrintCandidate(long candidateId, long? vacancyId)
        {
            try
            {
                var candidate = GetCandidatePrint(candidateId, vacancyId);
                if (candidate.Candidate.Count == 0)
                    return;
                var printPreviewXtraForm = new PrintPreviewXtraForm();
                printPreviewXtraForm.Setup(candidate, "Candidate.rpt");
                printPreviewXtraForm.ShowDialog();
            }
            catch (Exception e)
            {
                PublishAndShowErrorMessage(e, "Não foi possível imprimir a informação sobre o candidato.");
            }
            
        }

        public void SetCandidateAction(string state, long candidateId)
        {
            var form = new ChangeStateXtraForm {Date = DateTime.Now};
            if (form.ShowDialog() != DialogResult.OK)
                return;
            FixConnection();
            var sqlTransaction = _connection.BeginTransaction();
            try
            {
                Database.InsertAction(sqlTransaction, candidateId, state, form.Reason, form.Remarks, form.Date, form.Interviewer);
                Database.UpdateCandidateStatus(sqlTransaction, candidateId, state);
                sqlTransaction.Commit();
                OnCandidateSaved();
            }
            catch (Exception e)
            {
                sqlTransaction.Rollback();
                PublishAndShowErrorMessage(e, "Não foi possível inserir a acção sobre o candidato.");
            }
        }

        public void UpdateCandidateAction(long actionId, string reason, string remarks, DateTime date, string interviewer)
        {
            FixConnection();
            var sqlTransaction = _connection.BeginTransaction();
            try
            {
                Database.UpdateAction(sqlTransaction, actionId, reason, remarks, date, interviewer);
                sqlTransaction.Commit();
                OnCandidateSaved();
            }
            catch (Exception e)
            {
                sqlTransaction.Rollback();
                PublishAndShowErrorMessage(e, "Não foi possível actualizar a acção sobre o candidato.");
            }
        }


        public OverviewDataSet GetCitiesCount()
        {
            FixConnection();
            var sqlTransaction = _connection.BeginTransaction();
            try
            {
                var dataSet = Database.GetCitiesTop(sqlTransaction);
                sqlTransaction.Commit();
                return dataSet;
            }
            catch (Exception e)
            {
                sqlTransaction.Rollback();
                PublishAndShowErrorMessage(e, "Não foi possível ler a lista de cidades topo.");
                return new OverviewDataSet();
            }
        }

        public OverviewDataSet GetPositionsCount()
        {
            FixConnection();
            var sqlTransaction = _connection.BeginTransaction();
            try
            {
                var dataSet = Database.GetPositionsTop(sqlTransaction);
                sqlTransaction.Commit();
                return dataSet;
            }
            catch (Exception e)
            {
                sqlTransaction.Rollback();
                PublishAndShowErrorMessage(e, "Não foi possível ler a lista de funções distintas.");
                return new OverviewDataSet();
            }
        }

        public OverviewDataSet GetSexCount()
        {
            FixConnection();
            var sqlTransaction = _connection.BeginTransaction();
            try
            {
                var dataSet = Database.GetSexCount(sqlTransaction);
                sqlTransaction.Commit();
                return dataSet;
            }
            catch (Exception e)
            {
                sqlTransaction.Rollback();
                PublishAndShowErrorMessage(e, "Não foi possível ler a lista de sexo distintas.");
                return new OverviewDataSet();
            }
        }

        public OverviewDataSet GetEducationCount()
        {
            FixConnection();
            var sqlTransaction = _connection.BeginTransaction();
            try
            {
                var dataSet = Database.GetEducationCount(sqlTransaction);
                sqlTransaction.Commit();
                return dataSet;
            }
            catch (Exception e)
            {
                sqlTransaction.Rollback();
                PublishAndShowErrorMessage(e, "Não foi possível ler a lista de habilitações distintas.");
                return new OverviewDataSet();
            }
        }

        public OverviewDataSet GetAgeCount()
        {
            FixConnection();
            var sqlTransaction = _connection.BeginTransaction();
            try
            {
                var dataSet = Database.GetAgeCount(sqlTransaction);
                sqlTransaction.Commit();
                return dataSet;
            }
            catch (Exception e)
            {
                sqlTransaction.Rollback();
                PublishAndShowErrorMessage(e, "Não foi possível ler a lista de idades distintas.");
                return new OverviewDataSet();
            }
        }

        #region Layout

        private ListaLayoutDataSet GetListLayouts(string list)
        {
            FixConnection();
            var sqlTransaction = _connection.BeginTransaction();
            try
            {
                var dataSet = Database.GetListLayouts(sqlTransaction, list);
                sqlTransaction.Commit();
                return dataSet;
            }
            catch (Exception e)
            {
                sqlTransaction.Rollback();
                PublishAndShowErrorMessage(e, "Não foi possível ler a lista de layouts da lista.");
                return new ListaLayoutDataSet();
            }
        }

        private static List<string> GetLayouts(ListaLayoutDataSet dataSet)
        {
            var layouts = new List<string>();
            foreach (var layout in dataSet.ListaLayout)
                layouts.Add(layout.Nome);
            return layouts;
        }

        private void SaveLayout(string lista, string nome, string xmlLayout)
        {
            FixConnection();
            var sqlTransaction = _connection.BeginTransaction();
            try
            {
                Database.SaveLayout(sqlTransaction, lista, nome, xmlLayout);
                sqlTransaction.Commit();
            }
            catch (Exception e)
            {
                sqlTransaction.Rollback();
                PublishAndShowErrorMessage(e, "Não foi possível gravar layout da lista.");
            }
        }

        public string LoadLayout(GridView gridView, string list)
        {
            try
            {
                var dataSet = GetListLayouts(list);
                var form = new LoadLayoutXtraForm { Layouts = GetLayouts(dataSet) };
                if (form.ShowDialog() != DialogResult.OK)
                    return "";
                var xmlLayout = dataSet.ListaLayout.FindByListaNome(list, form.LayoutName).XmlLayout;
                DevExpressHelper.RestoreLayoutFromXml(gridView, xmlLayout);
                return form.LayoutName;
            }
            catch (Exception)
            {
                return "";
            }
        }

        public string SaveLayout(IWin32Window owner, string list, string xmlLayout)
        {
            try
            {
                var dataSet = GetListLayouts(list);
                var form = new SaveLayoutXtraForm { OwnerWindow = owner, Layouts = GetLayouts(dataSet) };
                if (form.ShowDialog() != DialogResult.OK)
                    return "";
                SaveLayout(list, form.LayoutName, xmlLayout);
                return form.LayoutName;
            }
            catch (Exception)
            {
                return "";
            }
        }

        #endregion

        public void CloseConnections()
        {
            _connection.Close();
        }
    }
}